home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw / OffSample / UFailure.a < prev    next >
Encoding:
Text File  |  2000-09-28  |  11.6 KB  |  388 lines  |  [TEXT/MPS ]

  1. ;
  2. ;    Apple Macintosh Developer Technical Support
  3. ;
  4. ;    Exception handling for MPW Pascal, MacApp and MPW C
  5. ;
  6. ;    UFailure (aka Signals) - “Exceptional code, with a few exceptions.”
  7. ;
  8. ;    UFailure.a    -    Assembly Source
  9. ;
  10. ;    Copyright © 1985-1988 Apple Computer, Inc.
  11. ;    All rights reserved.
  12. ;
  13. ;    Versions:    1.0                    11/88
  14. ;
  15. ;    Components:    UFailure.p            November 1, 1988
  16. ;                UFailure.h            November 1, 1988
  17. ;                UFailure.inc1.p        November 1, 1988
  18. ;                UFailure.a            November 1, 1988
  19. ;
  20. ;    UFailure (or Signals) is a set of exception handling routines suitable for
  21. ;    use with MacApp, MPW C, and MPW Pascal. It is a jazzed-up version of the MacApp
  22. ;    UFailure unit. There is a set of C interfaces to it as well.
  23. ;
  24.  
  25.             PRINT    OFF
  26.             INCLUDE    'Traps.a'
  27.             PRINT    ON
  28.             
  29.             STRING    ASIS
  30.  
  31. ;=============================================================================================
  32.             GblA    &UsingMacApp
  33.     If        &TYPE('&Debugging') = 'UNDEFINED' Then
  34.             GblA    &Debugging
  35. &UsingMacApp    SetA    0            ; we assume we’re MacAppless if &Debugging isn’t defined 
  36.         If        &TYPE('&Debug') = 'UNDEFINED' Then
  37. &Debugging    SetA    0            ; default to debugging off
  38.         Else
  39. &Debugging    SetA    &Debug        ; use the makefile definition of &Debug
  40.         EndIf
  41.     Else    
  42. &UsingMacApp    SetA    1            ; we assume we have MA if &Debugging is defined 
  43.     EndIf
  44. ;=============================================================================================
  45.     If        &TYPE('Head') = 'UNDEFINED' Then
  46.         Macro    
  47.         Head
  48.                 GblA    &Debugging
  49.             If  &Debugging Then
  50.                 Link    A6,#0        ; These two instructions form a slow no-op
  51.                 Move.L    (SP)+,A6
  52.             EndIf
  53.         EndM
  54.     EndIf
  55. ;=============================================================================================
  56.     If        &TYPE('Tail') = 'UNDEFINED' Then
  57.         Macro    
  58.         Tail
  59.                 GblA    &Debugging
  60.             If  &Debugging Then
  61.                 Unlk    A6
  62.                 Rts
  63.                 DC.B    &Ord(&SubStr(&Syslst[1],2,1)) + $80
  64.                 DC.B    '&SubStr(&Syslst[1],3,7)'
  65.             EndIf
  66.         EndM
  67.     EndIf
  68. ;=============================================================================================
  69.         
  70. ; the following constant sets the limit on the depth of nested CatchSignals
  71. SigBlockSize EQU    8                            ;number of elements in block
  72.  
  73. CatchSigErr    EQU        200                            ;"insufficient heap" message
  74. SigElSize    EQU        72                            ;byte size of FailInfo record
  75. FrameRet    EQU        4                            ;return addr. for frame (off A6)
  76. SigBigA6    EQU        $FFFFFFFF                    ;A6 at outer level (for Pascal)
  77. nSavedRegs    EQU     11                            ;number of registers saved in FailInfo record
  78.  
  79. ; offsets into the FailInfo record (see UFailure.p)
  80. SigA6        EQU        36
  81. SigSP        EQU        40
  82. SigCode        EQU        44
  83. SigMessage    EQU        46
  84. SigFailA6    EQU        50
  85. SigFailPC    EQU        54
  86. whatSignals    EQU        66
  87. SigFRet        EQU        68
  88.  
  89.     
  90. ; The global data used by these routines follows. It is in the form of a 
  91. ; RECORD, but, unlike above, no origin is specified, which means that memory 
  92. ; space *will* be allocated.
  93. ; This data is referenced through a WITH statement at the beginning of the 
  94. ; procs that need to get at this data. Since the Assembler knows when it is 
  95. ; referencing data in a data module (since they must be declared before they 
  96. ; are accessed), and since such data can only be accessed based on A5, there 
  97. ; is no need to explicitly specify A5 in any code which references the data 
  98. ; (unless indexing is used).  Thus, in this program we have omitted all A5 
  99. ; references when referencing the data.
  100.  
  101. SigGlobals RECORD        ;no origin means this is a data record
  102.                         ;not a template(as above)
  103. SigEnd        DS.L    1    ;current end of table
  104. SigNow        DS.L    1    ;the current offset
  105. SigPointer    DC.L    0    ;the handle := 0 initially
  106.             ENDR    
  107.  
  108.  
  109.         If  &UsingMacApp Then
  110.             Seg     'MAInit'
  111.         EndIf
  112. InitSignals    PROC    EXPORT                        ;PROCEDURE InitSignals;
  113.             EXPORT    InitUFailure
  114.             IMPORT    gTopHandler:Data
  115.             IMPORT    gInitHandler:Data
  116.         If  &UsingMacApp And &Debugging Then
  117.             IMPORT    gAskAboutAlloc:Data
  118.             IMPORT    gAskFailure:Data
  119.         EndIf
  120.             WITH    SigGlobals
  121. ;the above statement makes the template SigElement and the global data 
  122. ;record SigGlobals available to this procedure
  123.  
  124.              Head
  125.             MOVE.L    #SigBigA6,A6                ;make A6 valid for Signal
  126. InitUFailure                                    ;PROCEDURE InitUFailure;
  127.             CLR.L    gTopHandler(A5)                ;nothing in the list
  128.             CLR.L    gInitHandler(A5)            ;MA has another list during initialization
  129.         If  &UsingMacApp And &Debugging Then
  130.             CLR.B    gAskAboutAlloc(A5)            ;set the MA debugging guys to FALSE
  131.             CLR.B    gAskFailure(A5)
  132.         EndIf
  133.  
  134.             MOVE.L    #SigBlockSize*SigElSize,D0
  135.             _NewPtr                                ;try to get a table
  136.             BNE.S    forgetit                    ;we couldn't get that!?
  137.             
  138.             MOVE.L    A0,SigPointer                ;save it
  139.             MOVE.L    #-SigElSize,SigNow            ;point "now" before start
  140.             MOVE.L    #SigBlockSize*SigElSize,SigEnd ;save the end
  141. forgetit    RTS
  142.         
  143.             Tail    'INITUFAI'
  144.             ENDP
  145.  
  146.  
  147.         If  &UsingMacApp Then
  148.             Seg     'MAMain'
  149.         EndIf
  150. CatchCFailures PROC    EXPORT                        ;pascal void CatchCFailures(FailInfo &fi, HandlerFuncPtr handler);
  151.             IMPORT    FailCEntry
  152.             
  153.             Head
  154.             MOVE.L    (A7)+,D2                    ;save return address
  155.             MOVEQ    #0,D1                        ;CatchCFailures used  (no A6 link, uses handler proc.)
  156.             BRA.S    FailCEntry                    ;finish from CatchFailures
  157.             Tail    'CATCHCFA'
  158.  
  159. CatchFailures PROC    EXPORT                        ;PROCEDURE CatchFailures(VAR fi: FailInfo;
  160. ;                                                    PROCEDURE Handler(code: INTEGER; message: LONGINT));
  161.             IMPORT    FailuresEntry
  162.             EXPORT    FailCEntry
  163.             WITH    SigGlobals
  164.             
  165.             Head
  166.             MOVE.L    (A7)+,D2                    ;save return address
  167.             ADDQ    #4,A7                        ;discard A6 link
  168.             MOVEQ    #-1,D1                        ;CatchFailures used  (maybe A6 link???, handler proc.)
  169. FailCEntry
  170.             MOVE.L    (A7)+,A1                    ;get handler address
  171.             MOVE.L    (A7)+,A0                    ;FailInfo record address
  172.             BRA.S    FailuresEntry                ;enter CatchSignal with D2, A0, A1 set
  173.             Tail    'CATCHFAI'
  174.  
  175. CatchSignal    PROC    EXPORT                        ;FUNCTION CatchSignal:INTEGER
  176.             IMPORT    SiggyPop2,Signal,SigDeath
  177.             IMPORT    gTopHandler:Data
  178.             EXPORT    FailuresEntry
  179.             WITH    SigGlobals
  180.             
  181.             Head
  182.             MOVE.L    (A7)+,A1                    ;grab return address for “handler” address
  183.             MOVE.L    A1,D2                        ;save return address
  184.             MOVEQ    #1,D1                        ;CatchSignals used; no A6 link needed on stack, no proc.
  185.             CLR.W    (A7)                        ;no error code (before its time)
  186.  
  187.             MOVE.L    SigPointer,D0                ;point to table
  188.             BEQ        SigDeath
  189.             MOVE.L    D0,A0
  190.             MOVE.L    SigNow,D0
  191.             ADD.L    #SigElSize,D0
  192.             MOVE.L    D0,SigNow                    ;save new position
  193.             CMP.L    SigEnd,D0                    ;have we reached the end?
  194.             BNE.S    catchit                        ;no, proceed
  195.             
  196. ;signals, we use 'em ourselves
  197.             MOVE.L    SigNow,SigEnd                ;restore old ending offset
  198.             MOVE.L    #SigElSize,D0
  199.             SUB.L    D0,SigNow                    ;ditto for current position
  200.             MOVE.W    #CatchSigErr,4(A7)            ;we'll signal a "couldn't
  201.                                                 ;  catch" error
  202.             JSR        Signal                        ;never returns of course
  203.                     
  204. catchit        
  205.             ADD.L    D0,A0                        ;point to new entry
  206. FailuresEntry                                    ;A0=pointer to FailInfo block,A1=handler address,
  207.                                                 ; D1=flag showing how we entered, D2=return address
  208.             MOVE.L    A0,D0                        ;save FailInfo record address
  209.  
  210.             MOVE.W    D1,whatSignals(A0)            ;remember what’s catching (-1=CatchFailures,
  211.                                                 ; 0=CatchCFailures, 1=CatchSignal)
  212.             BLE.S    @1                            ;can’t use frame to clean up if they’ll call Success
  213.  
  214.             CMP.L    #SigBigA6,A6                ;are we at the outer level?
  215.             BEQ.S    @1                            ;yes, no frame, no cleanup needed 
  216.             MOVE.L    FrameRet(A6),SigFRet(A0)    ;save old frame return
  217.                                                 ; address
  218.             LEA        SiggyPop,A0
  219.             MOVE.L    A0,FrameRet(A6)                ;set cleanup code address
  220.             MOVE.L    D0,A0                        ;restore FailInfo record address
  221. @1        
  222.             MOVEM.L A2-A7/D3-D7,(A0)            ;save all registers first (note that the saved
  223.                                                 ; stack points to the function result for CatchSignal)
  224.             ADD     #nSavedRegs*4,A0            ;advance pointer by # bytes regs
  225.         
  226.             CLR.W    (A0)+                        ;clear error field
  227.             CLR.L    (A0)+                        ;clear message field
  228.             CLR.L    (A0)+                        ;clear A6 link
  229.             
  230.             TST.W    D1                            ;was CatchFailures used?
  231.             BPL.S    @2                            ;no, CatchCFailures or CatchSignal; skip
  232.             MOVE.L    A6,-4(A0)                    ;save the A6Link
  233. @2
  234.             MOVE.L    A1,(A0)+                    ;save the handler ptr
  235.         
  236.             MOVE.L    gTopHandler(A5),(A0)+        ;Link the FailInfo into the list
  237.             MOVE.L    D0,gTopHandler(A5)
  238.             MOVE.L    D2,(A0)+                    ;remember the caller's PC for MA debugging
  239.  
  240.             MOVE.L    D2,A0                        ;get return address
  241.             JMP        (A0)
  242.             Tail    'CATCHSIG'
  243.  
  244.             ALIGN
  245. SiggyPop
  246.             Head
  247.             MOVE.L    D0,-(A7)                    ;save D0 in case we’re returning from a c function
  248.  
  249.             MOVE.L    SigPointer,A0
  250.             MOVE.L    A0,D0                        ;to set CCR
  251.             BEQ        SigDeath                    ;nil pointer means trouble
  252.             MOVE.L    SigNow,D0                    ;grab table offset to entry
  253.             BMI        SigDeath                    ;if no entries then give up
  254.             ADD.L    D0,A0                        ;point to current element
  255.             
  256.             MOVE.L    SigFRet(A0),-(A7)            ;push proc's real return address
  257.             BSR        SiggyPop2                    ;pop element and call Success to pop handler
  258.             MOVE.L    (A7)+,A1                    ;get proc’s return address
  259.             MOVE.L    (A7)+,D0                    ;get back D0 in case we’re returning from c
  260.             JMP        (A1)
  261.             Tail    'SIGGYPOP'
  262.             
  263.             ENDP
  264.  
  265.  
  266.  
  267.  
  268.         If  &UsingMacApp Then
  269.             Seg     'MAMain'
  270.         EndIf
  271. FreeSignal    PROC    EXPORT                        ;PROCEDURE FreeSignal;
  272.             IMPORT    SigDeath,Success
  273.             IMPORT    gTopHandler:Data
  274.             EXPORT    SiggyPop2
  275.             WITH    SigGlobals
  276.             
  277.             Head
  278.             MOVE.L    gTopHandler(A5),A0            ;point to FailInfo record
  279.             MOVE.L    A0,D0                        ;to set CCR
  280.             BEQ.S    SigDeath
  281.             
  282.             TST.W    whatSignals(A0)                ;was CatchSignal used?
  283.             BLE.S    SiggyPop3                    ;no, call Success and return
  284.             
  285.             MOVE.L    SigNow,D0                    ;grab table offset to entry
  286.             
  287.             MOVE.L    SigA6(A0),A1                ;get A6 at point of CatchSignal
  288.             CMP.L    #SigBigA6,A1                ;is it at the outer level?
  289.             BEQ.S    SiggyPop2                    ;yes, don't jam the address if no frame 
  290.             MOVE.L    SigFRet(A0),FrameRet(A1)    ;"pop" cleanup code
  291. SiggyPop2
  292.             SUB.L    #SigElSize,D0
  293.             MOVE.L    D0,SigNow                    ;"pop" the entry
  294. SiggyPop3
  295.             MOVE.L    A0,-(A7)                    ;push address for Success (FailInfo’s)
  296.             JSR        Success                        ;let MacApp remove FailInfo from list; return
  297.             RTS
  298.             Tail    'FREESIGN'
  299.             
  300.             ENDP
  301.  
  302.         If  &UsingMacApp Then
  303.             Seg     'MAMain'
  304.         EndIf
  305. SignalMessage PROC    EXPORT                        ;PROCEDURE SignalMessage(code: INTEGER; message: LONGINT);
  306.             IMPORT    SignalEntry
  307.             WITH    SigGlobals
  308.  
  309.             Head
  310.             MOVE.L    (A7)+,A1                    ;get return address    
  311.             MOVE.L    (A7)+,D0                    ;get message
  312.             BRA.S    SignalEntry
  313.             Tail    'SIGNALME'
  314.  
  315. Signal        PROC    EXPORT                        ;PROCEDURE Signal(code:INTEGER);
  316.             IMPORT    Failure
  317.             EXPORT    SigDeath,SignalEntry
  318. code        EQU        4
  319.             WITH    SigGlobals
  320.  
  321.             Head
  322.             MOVE.L    (A7)+,A1                    ;get return address    
  323.             CLR.L    D0                            ;message := 0
  324. SignalEntry
  325.             MOVE.W    (A7)+,D1                    ;get code
  326.             BNE.S    @0                            ;process the signal if code is non-zero
  327.             JMP    (A1)                            ;return to caller (code was 0)
  328. @0
  329.             MOVE.W    D1,-(A7)                    ;push code
  330.             MOVE.L    D0,-(A7)                    ;push message
  331.             JSR        Failure                        ;this will pop the handler and call SignalFailure
  332. SigDeath
  333.             _Debugger                            ;wasn’t supposed to come back…
  334.             Tail    'SIGNAL  '
  335.  
  336.             ENDP
  337.  
  338.         If  &UsingMacApp Then
  339.             Seg     'MAMain'
  340.         EndIf
  341. DoFailure    PROC    EXPORT                        ;PROCEDURE DoFailure(VAR fi: FailInfo);
  342.             IMPORT    Failure
  343. fi            EQU        4
  344.             
  345.             Head
  346.             BSR        FreeSignal                    ;pop this guy off (but the record is still valid)
  347.             
  348.             MOVE.L    fi(A7),A0                    ;get FailInfo record
  349.             
  350.             MOVEM.L (A0),A2-A7/D3-D7            ;restore regs (can't use A7 anymore)
  351.             ADD     #nSavedRegs*4,A0            ;advance pointer
  352.         
  353.             MOVE.W    (A0)+,D0                     ;get error
  354.         
  355.             TST.W    whatSignals-nSavedRegs*4-2(A0)    ;was CatchSignal used?
  356.             BGT.S    @2                            ;yes, skip
  357.             
  358.             MOVE.L    (A0)+,D1                     ;get message
  359.             MOVEM.L    D0/D1,-(SP)                    ;save error and message for later use
  360.  
  361.             MOVE.W    D0,-(SP)
  362.             MOVE.L    D1,-(SP)                    ;parameters to failure handler
  363.                 
  364.             MOVE.L    (A0)+,D0                    ;check the A6Link
  365.             BEQ.S    @1                            ;if NIL then don't pass it
  366.             MOVE.L    D0,-(SP)                    ;else do pass it
  367. @1
  368.             MOVE.L    (A0)+,A0                    ;get address of failure handler
  369.         
  370.             JSR     (A0)                        ;call failure handler
  371.             
  372.             MOVEM.L    (SP)+,D0/D1                    ;get error & message back
  373.             MOVE.W    D0,-(SP)
  374.             MOVE.L    D1,-(SP)                    ;parameters to Failure
  375.             JSR        Failure
  376.             _Debugger                            ;not supposed to fail to fail
  377.             
  378. @2
  379.             MOVE.W    D0,(A7)                        ;set CatchSignal function result
  380.             MOVE.L    8(A0),A0                    ;address of the failure handler-skip msg. & A6 link
  381.             JMP        (A0)                        ;go to point of CatchSignal
  382.             Tail    'DOFAILUR'
  383.             
  384.             ENDP
  385.                     
  386.  
  387.             END
  388.